/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package wifipositioner;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import org.pi4.locutil.GeoPosition;
import org.pi4.locutil.MACAddress;
import org.pi4.locutil.trace.SignalStrengthSamples;
import org.pi4.locutil.trace.TraceEntry;

/**
 *
 * @author pla
 */
public class ModelBasedMapGenerator 
{
    private ArrayList<GeoPosition> geoPositions;
    private HashMap<MACAddress, GeoPosition> macAddresses;
    
    public ModelBasedMapGenerator(double min_X, double min_Y, double max_X, double max_Y, double increment)
    {
        geoPositions = GeneratePositionGrid(min_X, min_Y, max_X, max_Y, increment);
        macAddresses = InitializeMACAddresses();    
    }
    
//    public HashSet<ModelBasedTrace> Generate(TraceEntry referenceTrace, double nFactor)
//    {
//        HashSet<ModelBasedTrace> generatedSignalStrengths = new HashSet<>();
//        HashMap<MACAddress,Double> referenceDistances = new HashMap<>();
//        HashMap<MACAddress,Double> accessPointSignalStrengths = new HashMap<>();
//        
//        SignalStrengthSamples ssSamples = referenceTrace.getSignalStrengthSamples();
//        
//        for(GeoPosition pos : geoPositions)
//        {
//            ModelBasedTrace theoreticalTrace = new ModelBasedTrace(pos);
//            
//            for(MACAddress accessPoint : ssSamples.getSortedAccessPoints())
//            {
//                if(macAddresses.containsKey(accessPoint))
//                {
//                    if(!accessPointSignalStrengths.containsKey(accessPoint))
//                        accessPointSignalStrengths.put(accessPoint, ssSamples.getAverageSignalStrength(accessPoint));
//                    if(!referenceDistances.containsKey(accessPoint))
//                        referenceDistances.put(accessPoint, referenceTrace.getGeoPosition().distance(macAddresses.get(accessPoint)));
//                    
//                    double accessPointSignalStrength = accessPointSignalStrengths.get(accessPoint); // P(d_0)
//                    double referenceDistToAccessPoint = referenceDistances.get(accessPoint); // d_0
//                    double distanceToAccessPoint = pos.distance(macAddresses.get(accessPoint)); // d
//                    double theoreticalSS = accessPointSignalStrength - (10 * nFactor * Math.log10(distanceToAccessPoint/referenceDistToAccessPoint));
//                    //double theoreticalSS = -33.77 - (10 * nFactor * Math.log10(distanceToAccessPoint/1));
//                    theoreticalTrace.getSignalStrengthSamples().put(accessPoint, theoreticalSS);
//                }
//            }
//            
//            generatedSignalStrengths.add(theoreticalTrace);
//        }
//        
//        return generatedSignalStrengths;
//    }
    
    public HashSet<ModelBasedTrace> Generate(TraceEntry referenceTrace, double nFactor)
    {
        HashSet<ModelBasedTrace> generatedSignalStrengths = new HashSet<>();
        HashMap<MACAddress,Double> referenceDistances = new HashMap<>();
        HashMap<MACAddress,Double> accessPointSignalStrengths = new HashMap<>();
        
        SignalStrengthSamples ssSamples = referenceTrace.getSignalStrengthSamples();
        
        for(GeoPosition pos : geoPositions)
        {
            ModelBasedTrace theoreticalTrace = new ModelBasedTrace(pos);
            
            for(MACAddress accessPoint : macAddresses.keySet())
            {
                double distanceToAccessPoint = pos.distance(macAddresses.get(accessPoint)); // d
                double theoreticalSS = -33.77 - (10 * nFactor * Math.log10(distanceToAccessPoint));
                theoreticalTrace.getSignalStrengthSamples().put(accessPoint, theoreticalSS);
            }
            
            generatedSignalStrengths.add(theoreticalTrace);
        }
        
        return generatedSignalStrengths;
    }
    
    private ArrayList<GeoPosition> GeneratePositionGrid(double min_X, double min_Y, double max_X, double max_Y, double increment)
    {
        ArrayList<GeoPosition> positions = new ArrayList<>();
        
        for(double x = min_X; x <= max_X; x += increment)
        {
            for(double y = min_Y; y <= max_Y; y += increment)
                positions.add(new GeoPosition(x, y));
        }
        
        return positions;
    }
    
    private HashMap<MACAddress, GeoPosition> InitializeMACAddresses()
    {
        HashMap<MACAddress, GeoPosition> addresses = new HashMap<>();
        addresses.put(MACAddress.parse("00:14:BF:B1:7C:54"), new GeoPosition(-23.626, -18.596));
        addresses.put(MACAddress.parse("00:16:B6:B7:5D:8F"), new GeoPosition(-10.702, -18.596));
        addresses.put(MACAddress.parse("00:14:BF:B1:7C:57"), new GeoPosition(8.596, -14.62));
        addresses.put(MACAddress.parse("00:14:BF:B1:97:8D"), new GeoPosition(8.538, -9.298));
        addresses.put(MACAddress.parse("00:16:B6:B7:5D:9B"), new GeoPosition(-1.93, -2.749));
        addresses.put(MACAddress.parse("00:14:6C:62:CA:A4"), new GeoPosition(4.035, -0.468));
        addresses.put(MACAddress.parse("00:14:BF:3B:C7:C6"), new GeoPosition(13.333, -2.69));
        addresses.put(MACAddress.parse("00:14:BF:B1:97:8A"), new GeoPosition(21.17, -2.69));
        addresses.put(MACAddress.parse("00:14:BF:B1:97:81"), new GeoPosition(32.398, -2.69));
        addresses.put(MACAddress.parse("00:16:B6:B7:5D:8C"), new GeoPosition(32.573, 13.86 ));
        addresses.put(MACAddress.parse("00:11:88:28:5E:E0"), new GeoPosition(7.135, 6.023));
        
        return addresses;
    }
}
